package ru.ifmo.network;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

/**
 * @author avhaliullin
 */
public class MainApp {
    private final Server server;
    private final UDPListener udpListener;
    private final UDPSender udpSender;

    private final FilesProvider filesProvider;
    private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

    public MainApp(AppConfigurator configurator) throws IOException {
        final AppConfiguration configuration = configurator.getConfig();
        if (configuration == null) {
            throw new RuntimeException("Null configuration!");
        }
        InetAddress address = null;
        for (InterfaceAddress add : configuration.getNetworkInterface().getInterfaceAddresses()) {
            if (add.getAddress() instanceof Inet4Address) {
                address = add.getAddress();
            }
        }

        if (address == null) {
            throw new RuntimeException("Can't find address");
        }

        final InetAddress finalAddress = address;

        final File dir = configuration.getDir();

        filesProvider = new FilesProvider() {
            public List<String> listFiles() {
                File[] files = dir.listFiles(new FileFilter() {
                    public boolean accept(File pathname) {
                        return !pathname.isDirectory();
                    }
                });
                List<String> res = new ArrayList<String>();
                for (File file : files) {
                    res.add(file.getName());
                }
                return res;
            }

            public File getFile(final String requiredName) {
                File[] res = dir.listFiles(new FilenameFilter() {
                    public boolean accept(File dir, String name) {
                        return name.equals(requiredName);
                    }
                });
                if (res.length != 1) {
                    return null;
                }
                return res[0];
            }
        };

        server = new Server(filesProvider, configuration.getListeningPort());
        final HostsStorage storage = new HostsStorage(configuration.getSendingPort());
        udpListener = new UDPListener(storage, configuration.getListeningPort());
        udpSender = new UDPSender(new HelloMessageProvider() {
            public HelloMessage message() {
                int hashCode = 0;
                List<String> files = filesProvider.listFiles();
                for (String file : files) {
                    hashCode += file.hashCode();
                }

                return new HelloMessage(
                        finalAddress.getHostAddress(),
                        configuration.getHostName(), hashCode);
            }
        }, configuration.getSendingPort());
        storage.setListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Logger.getAnonymousLogger().info(e.getActionCommand());
            }
        });
        new Thread(server).start();
        new Thread(udpListener).start();
        executor.scheduleWithFixedDelay(udpSender, 1, 1, TimeUnit.SECONDS);
        View view = new View(storage);
        view.setSize(800, 600);
        view.setVisible(true);
    }

    public static void main(String[] args) {
        try {
            new MainApp(new ConfiguratorWindow());
        } catch (Throwable t) {
            t.printStackTrace();
            System.exit(1);
        }
    }
}
